package cn.gson.querydsl.dao.impl;

import cn.gson.querydsl.dao.OneResultTransformer;
import cn.gson.querydsl.dao.Query;
import cn.gson.querydsl.dao.QueryHandler;
import jakarta.persistence.Tuple;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>****************************************************************************</p>
 * <ul style="margin:15px;">
 * <li>Description : OneQueryHandler</li>
 * <li>Version     : 1.0</li>
 * <li>Creation    : 2024年07月19日</li>
 * <li>@author     : ____′↘夏悸</li>
 * </ul>
 * <p>****************************************************************************</p>
 */
public class OneQueryHandler implements QueryHandler {
    private final SessionFactory sessionFactory;
    private final Class<?> returnType;
    private final Query query;
    private final boolean isNative;

    public OneQueryHandler(SessionFactory sessionFactory, Class<?> returnType, Query query, boolean isNative) {
        this.sessionFactory = sessionFactory;
        this.returnType = returnType;
        this.query = query;
        this.isNative = isNative;
    }

    @Override
    public Object doQuery(Method method, Object[] args) throws Throwable {
        List list = getQuery(query, args).setTupleTransformer(new OneResultTransformer(returnType)).getResultList();
        if (list.isEmpty())
            return returnEmpty();
        if (list.size() > 1)
            throw new IllegalArgumentException("查询结果有多条数据，接收类型错误：List 不能转化为 " + returnType.getName());
        return list.get(0);
    }

    private Object returnEmpty() {
        if (returnType == Map.class)
            return new HashMap<>();
        if (returnType == int.class || returnType == long.class || returnType == Integer.class || returnType == Long.class
            || returnType == short.class || returnType == Short.class)
            return 0;
        return null;
    }

    private org.hibernate.query.Query getQuery(Query query, Object[] args) {
        Session session = sessionFactory.openSession();
        org.hibernate.query.Query exeQuery = null;
        if (isNative) {
            exeQuery = session.createNativeQuery(query.value(), Tuple.class);
        } else
            exeQuery = session.createQuery(query.value(), Tuple.class);
        if (args != null)
            for (int i = 0; i < args.length; i++)
                exeQuery.setParameter(i + 1, args[i]);
        return exeQuery;
    }
}
